package com.yiduo.outpost.core.web.exception;

import com.yiduo.outpost.core.model.exception.ErrorConstants;
import com.yiduo.outpost.core.model.exception.RestException;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.DefaultErrorAttributes;
import org.springframework.context.MessageSource;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;

import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
@Slf4j
@AllArgsConstructor
public class WebFluxErrorAttributes extends DefaultErrorAttributes {

    private static final String ERROR_ATTRIBUTE = DefaultErrorAttributes.class.getName() + ".ERROR";

    private final MessageSource messageSource;

    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {

        Map<String, Object> errorAttributes = new LinkedHashMap<>();

        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_TIMESTAMP, new Date());
        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_REQUEST_ID, request.exchange().getRequest().getId());
        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_PATH, request.path());

        Throwable error = getError(request);

        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_STATUS, determineHttpStatus(request, error));
        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_MESSAGE, ExceptionHandlerChain.determineErrorMessage(messageSource, error));

        // 默认异常返回业务状态码：5000
        errorAttributes.put(ErrorConstants.ERROR_RESPONSE_REQUEST_CODE, 50000);                                                                // 业务异常码
        if (error instanceof RestException) {
            errorAttributes.put(ErrorConstants.ERROR_RESPONSE_REQUEST_CODE, error.getMessage());                                                 // 业务异常码
        }


        return errorAttributes;
    }

    private int determineHttpStatus(ServerRequest request, Throwable error) {

        int httpStatus = HttpStatus.INTERNAL_SERVER_ERROR.value();

        ResponseStatus responseStatus = AnnotatedElementUtils.findMergedAnnotation(error.getClass(), ResponseStatus.class);
        Object unwrappedError = request.attribute(ERROR_ATTRIBUTE).get();

        if (responseStatus != null) {
            httpStatus = responseStatus.value().value();
        } else if (unwrappedError instanceof ResponseStatusException) {
            httpStatus = ((ResponseStatusException) unwrappedError).getStatusCode().value();
        }
        return httpStatus;
    }

}